/**
 * @author Fatemeh Chegini 
 * @author Samuel Measho
 */
package myApp

import javax.servlet.http._
import javax.servlet.ServletConfig
import javax.servlet.ServletContext;
import javax.servlet.http._
import javax.servlet.AsyncContext
import javax.servlet.ServletConfig
import scala.xml._
import scala.collection.JavaConversions._
import scala.util.matching.Regex
import scala.xml._
import org.squeryl.KeyedEntity
import org.squeryl.SessionFactory
import org.squeryl.Session
import org.squeryl.adapters.H2Adapter
import myApp.routing._
import myApp.Template._
import myApp.persistence._
import myApp.session._
import scala.xml.PrettyPrinter
import scala.xml.NodeSeq
import scala.xml.Elem
import org.squeryl.PrimitiveTypeMode._
import org.squeryl.dsl.ast.LogicalBoolean
import org.squeryl.annotations.OptionType
import scala.collection.mutable.ListBuffer
import scala.collection.mutable.Queue
import java.util.concurrent.ConcurrentLinkedQueue




class MyApplication extends HttpServlet{
  
 
  
   type HandlerFunction = (HttpServletRequest, HttpServletResponse) => Unit
   val routing = new Routing()
   val template=new Template() 
   val persistence = new Persistence()
   
   val session=new SessionManagement()
   
     /** Write XML back in a response. */
  def writeXML(resp: HttpServletResponse, ns: NodeSeq) = resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(ns))
   

  
  override def init(config: ServletConfig) {
	  super.init(config)
	  
	  //Starting the database
	  Class.forName("org.h2.Driver")

	  SessionFactory.concreteFactory = Some(() =>
	  Session.create(
			  java.sql.DriverManager.getConnection("jdbc:h2:" + System.getProperty("user.dir") + "/test;AUTO_SERVER=TRUE","sa","sa"),
			  new H2Adapter))
//	transaction {
//      Forum.drop
//    }
//
//    transaction {
//      Forum.create
//    }
			  
			  
	  //fill the buffer
			if (fullmessages.length==0){
			  { 
			  transaction {
				  for (a <- Forum.messages)	
					  fullmessages+=MessageDate(a.message, new java.util.Date)
			  }
			  }
			  
			}
			  
	
	  // adding routing  
	  routing.addRoute("/", SignIn)
	  routing.addRoute("/MyShop.css", css)
	  
      routing.addRoute("/Signin", SignIn)
      routing.addRoute("/test", session.justSession)
      routing.addRoute("/SignUp", SignOut)
      routing.addRoute("/listUser", getAllUsers)
      routing.addRoute("/script.js", js)

     routing.addRoute("/newMessage", allmessages)
     routing.addRoute("/information", info)
     
     
     routing.addRoute("/messages", messages)
     
     
     routing.addRoute("/update", updatemessage)
     routing.addRoute("/socket", socketmessage)
     routing.addRoute("/poll", pollmessage)
     routing.addRoute("/chatServlet", ChatServlet)  
     
  }

   
  override def service(req: HttpServletRequest, resp: HttpServletResponse) {
     //Session setup
    var currentContext = session.getCurrentContext
    currentContext = session.newContext(req, resp, currentContext)
    currentContext().session.setMaxInactiveInterval(100)
    if(currentContext().session.isNew()){
     loadHome(req,resp)
    }
  
    
    //Routing dispatch
    if (routing.tableDispatch(req, resp))
      return
    resp.sendError(HttpServletResponse.SC_NOT_FOUND)

  }
 
  
   def ChatServlet(req: HttpServletRequest, resp: HttpServletResponse) = {
	   resp.setContentType("text/html")
        resp.getWriter.write("<!DOCTYPE html>")
        writeXML(resp, chatPage)
  }
  
  
  
  
   def updatemessage(req: HttpServletRequest, resp: HttpServletResponse) = {
   
   val msg = req.getParameter("message")
        println("   message = " + msg)
        // Record the message and update anyone who's waiting on us
        fullmessages += MessageDate(msg, new java.util.Date)
        update
        resp.setStatus(200)
        resp.setContentLength(0)
        resp.setContentType("application/xml")
  }
   def socketmessage(req: HttpServletRequest, resp: HttpServletResponse) = {
   
   // Save the connection context in a queue.
        val c = req.startAsync
        c.setTimeout(0) // keep collection alive forever
        contexts offer c
  }
  
   def pollmessage(req: HttpServletRequest, resp: HttpServletResponse) = {
   
           sendMessages(resp)
  }
  
  def loadHome(req: HttpServletRequest, resp: HttpServletResponse) = {
   
    val xml = template.loadPage("index.html")
    val html = prepareForm(xml)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
  }
  
  
   def info(req: HttpServletRequest, resp: HttpServletResponse) = {
   
    val xml = information
    val html = prepareForm(xml)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
  }
  
    
   def messages(req: HttpServletRequest, resp: HttpServletResponse) = {
   
    val xml = allM
    val html = prepareForm(xml)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
  }
  
  def css(req: HttpServletRequest, resp: HttpServletResponse) {
    
    val css = template.loadCss("MyShop.css")
    resp.getWriter.write(css)
    resp.setContentType("text/css")
  }
   def js(req: HttpServletRequest, resp: HttpServletResponse) {
    
    val css = template.loadJs("script.js")
    resp.getWriter.write(css)
    resp.setContentType("text/javascript")
    
    
    
    
  }
   
def information={
				var nameUser=	session.getCurrentContext().session.getAttribute("name")
      			var lastName=	session.getCurrentContext().session.getAttribute("last")
      			
      			var emailuser=	session.getCurrentContext().session.getAttribute("email")
  
<html>
<head>
<title>Message</title>
<link rel="stylesheet" type="text/css" href="MyShop.css" />

</head>
<body>
	
<section id="section">
	
	
		<h3>Information:</h3>
      	

      	<table border="1" id="notfillregister">
          <tr>
          
           <td><p>{nameUser} {lastName}</p>
         
          <p>{emailuser}</p>
          </td></tr>
        </table>
	
		
	</section>
<footer>
<p>
       Copyright Fatemeh Chegini - Samuel Measho - Last Updated: 30.04.2012
</p>

</footer>
</body>
</html> }
   
 def readJs(req: HttpServletRequest, resp: HttpServletResponse) = {
  

  val js = scala.io.Source.fromFile("src/main/scala/myApp/script.js").toArray
 resp.getWriter.write(js)
 resp.setContentType("text/javascript")
 }
 //
    // SignIn
 
  def SignIn(req: HttpServletRequest, resp: HttpServletResponse) {
	   
      //Session setup
  
    val xml = template.setUpTemplate("templateLogin.xml")
    val html = prepareForm(xml)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
  }
  
   def allmessages(req: HttpServletRequest, resp: HttpServletResponse) = {
   val xml = template.setUpTemplate("allmessages.xml")
    val html = prepareForm(xml)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
  }
  
  def getingMessage(message:String)={
    
    var toReturn: Option[Long] = None

    transaction {
      
      
      var res = from(Forum.messages)(c =>where(c.message === message)select (c.id))

      if (res != null)
        toReturn = res.headOption
   
    }
    
    toReturn match {
      case Some(id: Long) =>
        
        repeatation
      case _ =>
        if (message.isEmpty()){
          fillSignUp
         
          }
        else{
          
          
         showMessage(message)
        }
    }
    
  }
  
  def saveMessage(message:String, user_name:String, user_id:Long) = {
	transaction {
	  Forum.messages.insert(new Message(message,user_id,user_name)) 
	}
  }
  
  def getName():String = {
    return session.getCurrentContext().session.getAttribute("name").toString();
  }
  
  def getUserId():Long = {
    session.getCurrentContext().session.getAttribute("userid").toString().toInt
  }
  
  def showMessage(message:String)={
    
    var user_name:String	= getName
	var user_id:Long		= getUserId
    
	saveMessage(message, user_name, user_id)

    <html>
      <head>
        <title>
          message
        </title>
      </head>
      <body>
   		<header>
   		<font color="red">message</font>
   		</header>
   		<section>
        
        <font color="red">My message</font>
       
     	<p>message: {message}</p>
        <p>user_id: {user_id}</p>
     	<p>user_name: {user_name}</p>
     	<p><a href="/messages"> Discussion forum</a></p>
     
      </section>
      </body>
    </html>
    
  }
  
  def allM={
  
    <html>
      <head>
        <title>
          message
        </title>
      </head>
      <body>
   		<header>
   		
   		</header>
   		<section>
        
        <font color="red">all message</font>
        
     
     	<article id="article">

     	<table border="1">
          <tr>
           
            <th>message</th>
     		<th>user_id</th>
		 	<th>user_name</th>
          </tr>
          {
            persistence.getMessages
            
          }
        </table>
</article>
      </section>
      </body>
    </html>
    
  }
  //handler function for SignIn

   def log(email: String, pass: String) = {
     
    if(!session.getCurrentContext().session.isNew() ){
      
    }    

    var toReturn: Option[Long] = None
    var check:Option[String]=None
    var check1:Option[String]=None
   
    transaction {
      var res = from(Forum.forum_users)(c =>
        where(c.email === email and c.pass === pass)
          select (c.id))
      
      if (res != null)
        toReturn = res.headOption
        
        
      var name=from(Forum.forum_users)(a=>where(a.email === email and a.pass === pass)select (a.name))
      
      
      var lastname=from(Forum.forum_users)(a=>where(a.email === email and a.pass === pass)select (a.last))
   if (name != null & lastname!=null)
        check = name.headOption
        check1=lastname.headOption
    }

    toReturn match {
      case Some(id: Long) =>
        check match{
          case Some(name:String)=>
            check1 match{
          		case Some(lastname:String)=>
          			correctPass(name,lastname)
          		case _=> wrongPass	//TODO:you should edit the html file
          			}
          case _=> wrongPass//TODO:you should edit the html file
        }
       
      case _ =>
        wrongPass

    }
  }
  def wrongPass = {
    
    <html>
      <head>
	  <link rel="stylesheet" type="text/css" href="MyShop.css" />
        <title>
          Wrong Pass
        </title>
      </head>
      <body>
	  <section id="notfillregister">
        <font color="red">Wrong Pass</font>
        <p>the password or the username is wrong</p>
        <form method="post" action="/Signin">
          <p>
            <input type="submit" value="Retry"/>
          </p>
        </form>
	  </section>
      </body>
    </html>
  }

  def correctPass(name:String,lastname:String) = {
    
     var justRememberUserEmail: Option[Long] = None
      var justEmail: Option[String] = None
     var check_id:Option[Long] = None
    transaction{
    var userEmail=from(Forum.forum_users)(a=>where(a.name === name and a.last === lastname)select (a.id))
    var Email=from(Forum.forum_users)(a=>where(a.name === name and a.last === lastname)select (a.email))
    
    if (userEmail != null&Email!=null)
        justRememberUserEmail = userEmail.headOption
        justEmail = Email.headOption
    }
     
     
   justRememberUserEmail match {
     
      case Some(id: Long) =>
        justEmail match{
          case Some(email: String)=>
      				session.getCurrentContext().session.setAttribute("name",name)
      				session.getCurrentContext().session.setAttribute("last",lastname)
      				session.getCurrentContext().session.setAttribute("userid",id)
      				session.getCurrentContext().session.setAttribute("email",email)
          case _=>
      				}
      	
      case _ =>
   }
   
     
    
     
    <html>
      <head>
       <link rel="stylesheet" type="text/css" href="MyShop.css" />
        <title>
          {name} {lastname} 
        </title>
      </head>
          
      <body>
       <header>
       </header>
          
        <nav id="nav" color="grean"><font color="green"> Welcome {name} {lastname}</font><a href="/information"  color="grean"> Info</a><a href="/"  color="grean"> logout</a></nav>
      

     <section id ="section">
       <article id="article1">
        

        <p>
        	<iframe src="/chatServlet" id="iframe">
        		<p>Your browser does not support iframes.</p>
        	</iframe>
        </p>


        
        
        <div id="messages/"></div>
       </article>
        
       <aside id ="aside">
        <img id="myImage1" src="http://www.rmcdocs.com/images/DiscussionForum.jpg" alt="myImage"/> 
        </aside>

     </section> 
     </body>
    </html>
  } 
  
  
  
  
  
  
  def goOut(req: HttpServletRequest, resp: HttpServletResponse){
  
     val xml = template.loadPage("index.html")
    val html = prepareForm(xml)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
    
    
  }
   
  
  //SignOut function
  def SignOut(req: HttpServletRequest, resp: HttpServletResponse) {
 
    val xml = template.setUpTemplate("templateSignUp.xml")
    val html = prepareForm(xml)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
  }
  
  
   def Register(name: String,last:String,email:String, pass: String) = {

    var toReturn: Option[Long] = None

    transaction {
      
      
      var res = from(Forum.forum_users)(c =>
        where(c.email === email)
          select (c.id))

      if (res != null)
        toReturn = res.headOption
   
    }
    
    toReturn match {
      case Some(id: Long) =>
        
        repeatation
      case _ =>
        if (name.isEmpty()|| last.isEmpty()|| email.isEmpty()|| pass.isEmpty()){
          fillSignUp
         
          }
        else{
          
          
         LogOut(name,last,email,pass)
        }
    }
  }
   //handler function for SignOut
  def LogOut(name: String,last:String ,email:String ,pass: String) = {
    
    transaction {
            Forum.forum_users.insert(new User(name,last, email, pass))
          }
    <html>
      <head>
    	 <link rel="stylesheet" type="text/css" href="MyShop.css" />
        <title id= "title"> Registration Complete</title>
      </head>
      <body>
	   <h1>Congratulations {name}</h1>
        
        <section id = "section">
       
       
        <h2>Your Account details are the following</h2>
         
        <p> First Name : {name} </p>
        <p> Last Name : {last} </p>
        <p> Email: {email}</p>
        <h2>your registration is complete!</h2>
        <form method="post" action="/Signin">
          <p>
            <input type="submit" value="signIn"/>
          </p>
        </form>
        </section>
      <footer id ="footer">
      <p>
		  Copyright Fatemeh Chegini - Samuel Measho - Last Updated: 30.04.2012
	  </p>
      </footer>
      </body>
    </html>
  }
  
  
   def fillSignUp = {
     
    <html>
      <head>
	   
	   <link rel="stylesheet" type="text/css" href="MyShop.css" />
        <title>
          SignUp Again
        </title>
      </head>
      <body width="1000" height="1000">
      <header>
      </header>
<section>
	   	<table border="5" id="notfillregister">

	   <tr><td>
        	<font color="red">SignUp Again</font>
        		<p>You should fill all text box which has *</p>
        	<form method="post" action="/SignUp">
          		<p><input type="submit" value="Retry"/></p>
        	</form>
	   </td></tr>
	   </table>
 </section>      
      </body>
    </html>
  }
  
   
     def repeatation = {
       
    <html>
      <head>
	    <link rel="stylesheet" type="text/css" href="MyShop.css" />
        <title>
          Reapitation Name
        </title>
      </head>
     <body width="1000" height="1000">
	   
        
	   <section>
	   	<table border="5" id="notfillregister">

	   <tr><td>
        	<font color="red">Please change the email.</font>
        		<p>Email is not available</p>
        	<form method="post" action="/SignUp">
          <p>
            <input type="submit" value="Retry"/>
          </p>
        </form>
	   </td></tr>
	   </table>
	   </section>      

      </body>
    </html>
  }

 def getAllUsers(req: HttpServletRequest, resp: HttpServletResponse) {
  
    val xml = ListUsers
    val html = prepareForm(xml)
    resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
  }
 
 
 //show all accounts
 def ListUsers = {
   
    <html>
      <head>
        <title>Accounts:</title>
      </head>
      <body>
        <h3>All accounts</h3>
        <table border="1">
          <tr>
            <th>Name</th>
            <th>Email</th>
		 	<th>password</th>
          </tr>
          {
            persistence.getUsers
            
          }
        </table>
      </body>
    </html>
  }


  
  //FORM

  /**
   * Prepare the form
   * @param template The template of the form we are using
   * @return NodeSeq The template changed
   */
  def prepareForm(template: NodeSeq): NodeSeq = {
    import scala.xml.transform._
    import scala.xml.Null // hide scala.Null
    object MakeForm extends RewriteRule {
      override def transform(n: Node): Seq[Node] = n match {
        case form: Elem if form.label == "form" =>
          val Some(handler) = form.attribute("handler")
          var Some(method) = form.attribute("method")

          // Make the handler and install in routeTable
          val (uri, f: HandlerFunction) = makeHandler(handler.text)

          routing.addRoute(uri, f)

          // Add an action to the form.
          form % Attribute(None, "action", Text(uri), Null)
        case n => n
      }
    }
    template.map(ns => new RuleTransformer(MakeForm)(ns))
  }

  /**
   * Creates a new path with its corresponding function
   * @param s
   * @return String A new path
   * @return HandlerFunction The corresponding function
   */
  def makeHandler(s: String): (String, HandlerFunction) = {
    // Parse the handler string.
    val q = "^(\\w+)\\((.*)\\)$".r

    val (methodName, argNames) = s match {
      case q(methodName, argNames) => (methodName, argNames.split(",").map(_.trim))
      case _ => throw new RuntimeException("bad handler: " + s)
    }

    // Look for a method that takes the right number of strings.
    val method = this.getClass.getMethod(methodName, argNames.map(_ => classOf[String]): _*)
    val h = (req: HttpServletRequest, resp: HttpServletResponse) => {
      val result = method.invoke(this, argNames.map(k => req.getParameter(k)): _*)
      result match {
        case s: String =>
          resp.getWriter.write(s)
        case html: NodeSeq =>
          resp.getWriter.write(new PrettyPrinter(72, 2).formatNodes(html))
      }
    }
    (handlerURI(methodName), h)
  }

  /**
   * Constructs a new path with the method name
   * @param methodName The method that will be used as path
   */
  def handlerURI(methodName: String) = {
    "/" + methodName
  }
  
  
  /*******************************************************
   *******************************************************
   *******************************************************
   ***************All messages fo AJAX********************
   *******************************************************
   *******************************************************
   *******************************************************
   *******************************************************
   */
   /**
   * A queue of saved connection contexts. Use a concurrent queue since multiple threads will access it.
   * When a new event happens, all contexts in the queue are notified.
   */
  val contexts = new ConcurrentLinkedQueue[AsyncContext]

  /**
   * Saved messages. Each time a message is received here, we send to entire list back to the waiting clients.
   */
  val fullmessages = new ListBuffer[MessageDate]
  
  case class MessageDate(text: String, date: java.util.Date)

  /**
   * Send all the messages in a response.
   * Better would be to send only the messages they haven't seen, but that's harder to implement, both at the client and the server.
   */
  def sendMessages(resp: HttpServletResponse) = {
    
    val msg:String = fullmessages.reverse(0).toString()
	saveMessage(msg, getName, getUserId)
    
    val div = <ul>
                {
                  for (msg <- fullmessages.reverse) yield 
                  	<li class="message">
                  		<span class="time">{msg.date.toLocaleString}</span>
                  		<span class="text">{ msg.text }</span>
                  	</li>
                }
              </ul>

    resp.setContentType("text/html")
    resp.setStatus(HttpServletResponse.SC_OK)
    writeXML(resp, div)
  }

  /** Update all the waiting clients. This should clear the contexts queue. */
  def update = {
    println("   updating")

    while (!contexts.isEmpty) {
      contexts.poll match {
        case null =>
        case c =>
          println("   update " + c)
          c.getResponse match {
            case resp: HttpServletResponse => sendMessages(resp)
            case _ => // not an HTTP servlet -- should not happen
              throw new MatchError
          }
          c.complete // close the connection
      }
    }
  }
  
def chatPage: NodeSeq = {
    val js = """
      function updateMessages(xml) {
        $("div#messages").html(xml);
      }
      
      function poll() {
        $.get("/poll", function (x) { updateMessages(x); });
      }

      // Long poll with a 30 second timeout.
      function longPoll() {
        $.ajax({ url: "/socket", success: function (x) { updateMessages(x); }, dataType: "html", complete: longPoll, timeout: 30000 });
      }

      $(document).ready(function() {
        $("form#chat").submit(function () {
          var msg = $("input#message").val();
          $("label#sent").html("Sent " + msg);
          $("input#message").val("");
          $.get("/update", { message: msg });
          return false;
        });
      });
      
      $(document).ready(function() {
          // setInterval(poll, 2000);
          poll(); // get the initial messages
          longPoll(); // wait for more
      });
   """

      val css = """
#messages ul {
          list-style-type: none;
        margin-bottom: 1em;
}
#messages ul li {
        width: 100%;
        padding-bottom: .25em;
}
        #messages ul li.message span.time {
        font-size: smaller;
        color: #ccc;
  }
"""
        
    <html>
      <head>
        <title>MicroBlog Forum</title>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js" type="text/javascript"/>
        <script type="text/javascript">{ new Unparsed(js) /* use Unparsed to avoid escaping " to &quot; */ }</script>
    <style type="text/css">{ new Unparsed(css) }</style>
      </head>
      <body>
        <h3><font color="#CC0000">MicroBlog Forum </font></h3>
        <form id="chat" action="">
          <fieldset>
            <label for="message">Enter your message:</label>
    		
            <input type="text" name="message" id="message"/>

            <label for="message" id="sent"/>
            <br/>
            <input type="submit" name="submit" id="submit" value="Send"/>
          </fieldset>
        </form>
        <div id="messages"/>
    	<div id="debug"/>
      </body>
    </html>
  }

  
  
  /**
   * 
   * 
   */
  
  
  
  
  
  
  
}